﻿using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using NiuX.LightServer.Options;

namespace NiuX.LightServer.Handlers
{
    /// <summary>
    /// 跨域处理器
    /// </summary>
    public class CorsHandler
    {
        public static async Task Handle(CorsOptions corsOption, HttpContext http)
        {
            var req = http.Request;
            var resp = http.Response;
            var method = http.Request.Method;

            if (corsOption.IsAllowAll)
            {
                return;
            }

            if (!req.Headers.TryGetValue("Origin", out var origin))
            {
                throw new CorsException();
            }

            //检查origin
            var originVal = origin.FirstOrDefault();

            if (!corsOption.IsAllowOrigin(originVal))
            {
                throw new CorsException();
            }

            AddHeader(true, HeaderConsts.AccessControlAllowOrigin, corsOption.IsAllAccessControlAllowOrigins ? "*" : originVal);
            AddHeader(corsOption.AccessControlAllowCredentials, HeaderConsts.AccessControlAllowCredentials, "true");
            AddHeader(corsOption.AccessControlExposeHeaders.IsNotNullOrNotWhiteSpace(), HeaderConsts.AccessControlExposeHeaders, corsOption.AccessControlExposeHeaders);

            if (method.IsNotEqual("OPTIONS"))
            {
                throw new CorsException();
            }

            AddHeader(
                req.Headers.TryGetValue(HeaderConsts.AccessControlRequestMethod, out var accessMethods) &&
                corsOption.IsAllowMethod(accessMethods.FirstOrDefault()), HeaderConsts.AccessControlAllowMethods,
                corsOption.AccessControlAllowMethods);
            AddHeader(
                req.Headers.TryGetValue(HeaderConsts.AccessControlAllowMethods, out var accessHeaders) &&
                corsOption.IsAllowHeader(accessHeaders.FirstOrDefault()), HeaderConsts.AccessControlAllowHeaders,
                corsOption.AccessControlAllowHeaders);
            AddHeader(corsOption.AccessControlMaxAge.HasValue, HeaderConsts.AccessControlMaxAge,
                corsOption.AccessControlMaxAge.ToString());

            await resp.WriteAsync("");

            void AddHeader(bool condition, string key, StringValues value)
            {
                if (condition)
                {
                    resp.Headers.Add(key, value);
                }
            }
        }


    }

    /// <summary>
    /// 跨域异常
    /// </summary>
    public class CorsException : Exception
    {

    }
}
